package com.huarui.permission.service.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;

import com.huarui.company.action.CertifyAction;
import com.huarui.companypackage.model.Service;
import com.huarui.permission.dao.PermissionDao;
import com.huarui.permission.dataobject.Action;
import com.huarui.permission.dataobject.Permission;
import com.huarui.permission.dataobject.Role;
import com.huarui.permission.dataobject.RoleTemplate;
import com.huarui.permission.service.PermissionService;
import com.huarui.user.security.UserHolder;

public class PermissionServiceImpl implements PermissionService {
	private static final Logger logger = Logger.getLogger(CertifyAction.class);
	private JdbcTemplate jdbcTemplate;

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	private List<Permission> permissionsGranted2LoginedUser;

	private List<Integer> permissionsIdGranted2LoginedUser;

	public PermissionDao permissionDao;
	private TransactionTemplate transactionTemplate;

	private List<Action> actionsGranted2LoginedUser;

	private List<Integer> permissionIdsGranted2AuthenticationCompany;

	private List<Permission> permissionIdsGranted2AllCompany;

	@SuppressWarnings("unchecked")
	public void init() {

		actionsGranted2LoginedUser = jdbcTemplate
				.query(" select id, actionName,methodName,permissionId from action where permissionId in"
						+ "( select distinct permissionId from permissionService where serviceId in"
						+ "( select id from service where target=0 ))",
						new RowMapper() {

							@Override
							public Object mapRow(ResultSet rs, int rowNum)
									throws SQLException {
								Action action = new Action();
								action.setId(rs.getInt(1));
								action.setActionName(rs.getString(2));
								action.setMethodName(rs.getString(3));
								action.setPermissionId(rs.getInt(4));
								return action;
							}
						});

		permissionsIdGranted2LoginedUser = jdbcTemplate.queryForList(
				"select distinct permissionId from permissionService where serviceId in"
						+ "( select id from service where target=0 )",
				Integer.class);

		permissionIdsGranted2AllCompany = jdbcTemplate
				.queryForList(
						" select distinct permissionId from permissionService where serviceId in ("
								+ "( select distinct serviceId from packageService where packageId in "
								+ " ( select id from package where isGift=1 and giftCondition=0)))",
						Integer.class);

		permissionIdsGranted2AuthenticationCompany = jdbcTemplate
				.queryForList(
						" select distinct permissionId from permissionService where serviceId in ("
								+ "( select distinct serviceId from packageService where packageId in "
								+ " ( select id from package where isGift=1 and giftCondition=1)))",
						Integer.class);

	}

	public TransactionTemplate getTransactionTemplate() {
		return transactionTemplate;
	}

	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}

	public void setPermissionsIdGranted2LoginedUser(
			List<Integer> permissionsIdGranted2LoginedUser) {
		this.permissionsIdGranted2LoginedUser = permissionsIdGranted2LoginedUser;
	}

	public PermissionDao getPermissionDao() {
		return permissionDao;
	}

	public void setPermissionDao(PermissionDao permissionDao) {
		this.permissionDao = permissionDao;
	}

	@Override
	public int hasPermission(Integer permissionId) {

		if (permissionsIdGranted2LoginedUser.contains(permissionId)) {

			return RESULT_HAS_PERMISSION;
		}

		List<Integer> roleIds = getRoleIds(UserHolder
				.getCurrentSessionMessage().getEmployeeId());

		if (roleIds == null || roleIds.isEmpty()) {
			return RESULT_NO_PERMISSION;
		}

		return permissionDao.hasPermission(permissionId, roleIds);
	}

	/*
	 * @Override public int hasPermission(String permissionName) {
	 * 
	 * return hasPermission(UserHolder.getCurrentSessionMessage().getUserId(),
	 * permissionName); }
	 */

	@Override
	@SuppressWarnings("unchecked")
	public int hasPermission(Integer employeeId, Integer permissionId) {
		String sql = "select permissionId from rolePermission where permissionId=? and roleId in (select roleId from roleEmployee where employeeId=?) union select permissionId from permissionService where permissionId=? and serviceId in (select id from service where target="
				+ Service.SERVICE_TARGET_COMMON_USER + ")";
		List permissions = jdbcTemplate.queryForList(sql, new Object[] {
				permissionId, employeeId, permissionId });
		return CollectionUtils.isEmpty(permissions) ? RESULT_NO_PERMISSION
				: RESULT_HAS_PERMISSION;
	}

	/*
	 * @Override public int hasPermission(Integer userId, String permissionName)
	 * { throw new RuntimeException(); }
	 */

	@Override
	public List<Integer> getRoleIds(Integer userId) {
		return permissionDao.getRoleIds(userId);
	}

	@Override
	public List<Integer> getRoleIds() {
		return getRoleIds(UserHolder.getCurrentSessionMessage().getUserId());
	}

	/**
	 * add by sunpeng.thx
	 * 
	 * @return
	 */
	public List<Integer> getCurrentUserPermissionIds() {
		Integer employeeId = UserHolder.getCurrentSessionMessage()
				.getEmployeeId();
		return permissionDao.getPermissionIds(employeeId == null ? 0
				: employeeId);
	}

	public boolean createDefaultRolesAndPermissions(final Integer companyId,
			final Integer companyType) {

		try {

			transactionTemplate.execute(new TransactionCallback() {

				@Override
				public Object doInTransaction(TransactionStatus status) {

					List<RoleTemplate> roleTemplates = permissionDao
							.getRoleTemplates(1, companyType);

					List<Role> roles = permissionDao.createRoles(roleTemplates,
							companyId);

					for (int i = 0; i < roles.size(); i++) {
						permissionDao.perparePermissions(roleTemplates.get(i),
								roles.get(i));

					}

					return null;
				}
			});
		} catch (RuntimeException e) {

			logger.debug(e.getMessage());
			return false;
		}

		return true;
	}

	public boolean createDefaultPermissions(final Integer companyId,
			final Integer donateType) {

		try {

			transactionTemplate.execute(new TransactionCallback() {

				@Override
				public Object doInTransaction(TransactionStatus status) {

					List<Role> roles = permissionDao
							.grantCompanyAllRole(companyId);

					for (int i = 0; i < roles.size(); i++) {
						permissionDao.perparePermissions(roles.get(i),
								donateType);

					}

					return null;
				}
			});
		} catch (RuntimeException e) {
			e.printStackTrace();
			logger.debug(e.getMessage());
			return false;
		}

		return true;
	}

	@Override
	public boolean createDefaultRolesAndPermissions() {

		final Integer companyId = UserHolder.getCurrentSessionMessage()
				.getCompanyId();
		final Integer companyType = UserHolder.getCurrentSessionMessage()
				.getCompanyType();

		return createDefaultRolesAndPermissions(companyId, companyType);

	}

	@Override
	public boolean resume2default(Integer companyId) {

		return permissionDao.deleteAllRolesAndPermission(companyId)
				&& createDefaultRolesAndPermissions();
	}

	@Override
	public List<Permission> getPermissionsGranted2LoginedUser() {
		return permissionsGranted2LoginedUser;
	}

	/*
	 * @Override public Action findAction(String action, String method) {
	 * 
	 * return permissionDao.findAction(action,method); }
	 */

	@Override
	public List<Action> getActionsGranted2LoginedUser() {

		return actionsGranted2LoginedUser;
	}

	@Override
	public List<Integer> getFreePermissionIdsGranted2AuthenticationCompany() {

		return permissionIdsGranted2AuthenticationCompany;
	}

	@Override
	public List<Permission> getFreePermissionIdsGranted2AllCompany() {
		return permissionIdsGranted2AllCompany;
	}

	@Override
	public List<Permission> getPermissionsGranted2AnonymousUser() {
		throw new RuntimeException();
	}

	/**
	 * 赠送免费套餐给新注册公司
	 * 
	 * @param companyId
	 * @param donateType
	 *            1/0:已认证公司/新注册公司
	 */
	public void donateFreePackage2Company(final Integer companyId,
			final Integer donateType) {

		jdbcTemplate.update(new PreparedStatementCreator() {

			@Override
			public PreparedStatement createPreparedStatement(Connection con)
					throws SQLException {
				final String sql = "insert into companyService"
						+ "(companyId , serviceId , serviceCode, serviceName , gmtBegin, gmtEnd)"
						+ " select "
						+ companyId.toString()
						+ ", s.id , s.code , s.name , now(), DATE_ADD(now(), INTERVAL ps.duration MONTH) "
						+ " from service s , packageService ps"
						+ " where s.id=ps.serviceId and ps.packageId in "
						+ "(select id from package where isGift=1 and giftCondition=? and gmtBegin<now() and gmtEnd>now())";
				PreparedStatement ps = con.prepareStatement(sql);
				ps.setInt(1, donateType);

				return ps;
			}
		});

	}

	/**
	 * 赠送免费套餐给新注册公司
	 * 
	 * @param companyId
	 */
	public void donateFreePackage2NewRegistCompany(Integer companyId) {
		donateFreePackage2Company(companyId, 0);
	}

	/**
	 * 赠送免费套餐给新认证公司
	 * 
	 * @param companyId
	 */
	public void donateFreePackage2NewAuthCompany(Integer companyId) {
		donateFreePackage2Company(companyId, 1);
	}

	public void donateFreePackage2NewAuthCompany(Integer companyId,
			Integer donateType) {
		donateFreePackage2Company(companyId, donateType);
		createDefaultPermissions(companyId, donateType);
	}

	@Override
	public List<Role> grantCompanyAllRole(Integer companyId) {

		return permissionDao.grantCompanyAllRole(companyId);
	}

	@Override
	public void addCompanyAdminRole(Integer employeeId, Integer companyId) {
		permissionDao.addCompanyAdminRole(employeeId, companyId);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void assignPackage2AuthCompany(final Integer companyId,
			final Integer packageId) {

		transactionTemplate.execute(new TransactionCallback() {

			@Override
			public Object doInTransaction(TransactionStatus status) {

				/**
				 * 
				 */
				/*
				 * List<Integer> serviceIds = jdbcTemplate .queryForList(
				 * "select ps.serviceId from packageService ps , companyService cs "
				 * +
				 * " where ps.serviceId=cs.serviceId and ps.packageId=? and cs.companyId=? "
				 * , new Object[] {packageId,companyId}, Integer.class);
				 * 
				 * if (!serviceIds.isEmpty()) { String errorInfo = String
				 * .format(
				 * "the company id:%d has buy some services belong to the package id:%d"
				 * , companyId, packageId); logger.error(errorInfo);
				 * 
				 * // throw new RuntimeException(errorInfo);
				 * 
				 * jdbcTemplate.update(new PreparedStatementCreator() {
				 * 
				 * @Override public PreparedStatement
				 * createPreparedStatement(Connection con) throws SQLException {
				 * final String sql=
				 * "update companyService set gmtEnd= DATE_ADD( gmtEnd , INTERVAL ps.duration MONTH)"
				 * + " where companyId=? and serviceId in ()"; return null; }
				 * });
				 * 
				 * return null; }
				 */

				/**
				 * 购买套餐中的服务，有的续费
				 */
				jdbcTemplate.update(new PreparedStatementCreator() {

					@Override
					public PreparedStatement createPreparedStatement(
							Connection con) throws SQLException {

						final String sql = "update companyService cs , packageService ps  set cs.gmtEnd= DATE_ADD( cs.gmtEnd , INTERVAL ps.duration MONTH) "
								+ "where  cs.companyId=? and cs.serviceId=ps.serviceId and ps.packageId=?";
						PreparedStatement ps = con.prepareStatement(sql);
						ps.setInt(1, companyId);
						ps.setInt(2, packageId);

						return ps;
					}
				});

				/**
				 * 购买套餐中的服务，新增
				 */
				jdbcTemplate.update(new PreparedStatementCreator() {

					@Override
					public PreparedStatement createPreparedStatement(
							Connection con) throws SQLException {

						final String sql = "insert into companyService"
								+ "(companyId , serviceId , serviceCode, serviceName , gmtBegin, gmtEnd)"
								+ " select  ? , s.id , s.code , s.name , now(), DATE_ADD(now(), INTERVAL ps.duration MONTH) "
								+ " from service s , packageService ps"
								+ " where s.id=ps.serviceId and ps.packageId=? and s.id not in ( select serviceId from companyService where companyId=?) ";
						PreparedStatement ps = con.prepareStatement(sql);
						ps.setInt(1, companyId);
						ps.setInt(2, packageId);
						ps.setInt(3, companyId);

						return ps;
					}
				});

				/*
				 * List<RoleTemplate> roles =
				 * jdbcTemplate.query("select * from role where companyId=?)",
				 * new Object[]{companyId} ,new RowMapper(){
				 * 
				 * @Override public Object mapRow(ResultSet rs, int rowNum)
				 * throws SQLException {
				 * 
				 * Role role = new Role();
				 * 
				 * role.setId(rs.getInt("id"));
				 * role.setEditable(rs.getInt("editable"));
				 * role.setIsAdministrator(rs.getInt("isAdministrator"));
				 * role.setName(rs.getString("name"));
				 * role.setRoleTemplateId(rs.getInt("roleTemplateId"));
				 * 
				 * return role; }});
				 */

				jdbcTemplate.update(new PreparedStatementCreator() {

					@Override
					public PreparedStatement createPreparedStatement(
							Connection con) throws SQLException {

						final String sql = "insert into rolePermission (roleId, permissionId) "
								+ "select r.id , rtp.permissionId from role r , roleTemplatePermission rtp"
								+ " where r.roleTemplateId=rtp.roleTemplateId and r.companyId=?"
								+ " and rtp.permissionId in ( select permissionId from permissionService ps1 , packageService ps2    "
								+ " where ps1.serviceId=ps2.serviceId and ps2.packageId=? ) "
								+ "and not exists ( select  * from rolePermission rp where r.id=rp.roleId and rp.permissionId=rtp.permissionId)";

						PreparedStatement ps = con.prepareStatement(sql);
						ps.setInt(1, companyId);
						ps.setInt(2, packageId);

						return ps;
					}
				});

				return null;
			}
		});

	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Integer> getServiceNewAuthCompany(Integer companyId,
			Integer donateType) {

		return (List<Integer>) jdbcTemplate
				.queryForList(
						"select cs.serviceId from packageService ps ,companyService cs "
								+ "where cs.serviceId=ps.serviceId and cs.companyId=? and ps.packageId in "
								+ "(select id from package where isGift=1 and giftCondition=? and gmtBegin<now() and gmtEnd>now())",
						new Object[] { companyId, donateType }, Integer.class);

	}

	@Override
	public void deleteRolePermissionWithComIdAndServiceId(
			final Integer companyId, final Integer serviceId) {

		transactionTemplate.execute(new TransactionCallback() {

			@Override
			public Object doInTransaction(TransactionStatus status) {

				jdbcTemplate.update(new PreparedStatementCreator() {

					@Override
					public PreparedStatement createPreparedStatement(
							Connection con) throws SQLException {

						final String sql = "delete rp1  from rolePermission rp1  inner join ("
								+ "select rp.roleId,rp.permissionId  from role r,rolePermission rp where r.id=rp.roleId and r.companyId=? "
								+ " and rp.permissionId in (select permissionId from permissionService where serviceId =?  and "
								+ "  permissionId  not in (select permissionId from permissionService where serviceId in"
								+ " (select serviceId from companyService where companyId=? and serviceId <>? "
								+ " and gmtBegin<=now() and gmtEnd>=now() )))) as  a "
								+ " on ( rp1.roleId=a.roleId and rp1.permissionId=a.permissionId)";

						PreparedStatement ps = con.prepareStatement(sql);
						ps.setInt(1, companyId);
						ps.setInt(2, serviceId);
						ps.setInt(3, companyId);
						ps.setInt(4, serviceId);

						return ps;
					}
				});

				return null;
			}
		});

	}

	@Override
	public void insertRolePermissionWithComIdAndServiceId(final Integer companyId,
			final Integer serviceId) {

		transactionTemplate.execute(new TransactionCallback() {

			@Override
			public Object doInTransaction(TransactionStatus status) {

				jdbcTemplate.update(new PreparedStatementCreator() {

					@Override
					public PreparedStatement createPreparedStatement(
							Connection con) throws SQLException {

						final String sql = "insert into rolePermission (roleId,permissionId)"
								+ "select r.id,rtp.permissionId from role r, roletemplatepermission rtp where r.roletemplateId=rtp.roletemplateId "
								+ "  and exists (select 1 from companyService cs, permissionService ps where cs.serviceId=? and  ps.serviceId=?"
								+ "  and cs.companyId=? and r.companyId =?  and rtp.permissionId=ps.permissionId )"
								+ " and not exists (select 1 from rolepermission rp where r.id=rp.roleId and rp.permissionId=rtp.permissionId  )";

						PreparedStatement ps = con.prepareStatement(sql);
						ps.setInt(1, serviceId);
						ps.setInt(2, serviceId);
						ps.setInt(3, companyId);
						ps.setInt(4, companyId);

						return ps;
					}
				});

				return null;
			}
		});

	}
	
	

}
